package cate.game.role.res.guild;

import cate.common.rpc.path.RpcCommonPath;
import cate.common.table.d.GDGuild;
import cate.common.table.d.GDNotice;
import cate.common.table.ins.InstanceRsRow;
import cate.common.util.GameResult;
import cate.common.util.XT;
import cate.game.GameBody;
import cate.game.chat.ChatContentParam;
import cate.game.db.GameMongoDao;
import cate.game.db.facade.KvLoader;
import cate.game.db.mongo.kv.KvMongo;
import cate.game.event.guild.GuildCreatedEvent;
import cate.game.framework.ModuleMan;
import cate.game.res.MixRes;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.farm.guildBoss.msg.MyGuildBossDataResp;
import cate.game.role.res.guild.boss.GuildBossRankCacheManager;
import cate.game.role.res.guild.boss.msg.GuildBossDataResp;
import cate.game.role.res.guild.handler.GuildManageAction;
import cate.game.role.res.guild.msg.GuildViewDetailResp;
import cate.game.role.res.guild.msg.rank.GuildRankResp;
import cate.game.role.res.guild.po.GuildPO;
import cate.game.role.res.guild.po.GuildRankItem;
import cate.game.role.res.guild.po.my.mall.GuildMallHandler;
import com.alibaba.druid.util.StringUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.rpc.RpcMsgHead;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import easy.java.struct.ref.StringRef;

import java.util.*;
import java.util.stream.Collectors;


@NoteClass(value = "公会管理")
public class GuildManager extends ModuleMan {
  public static final String MODULE_NAME = "guild-manager";

  public GuildSPO data;

  public GuildManager() {
  }

  public GuildMallHandler mallHandler = new GuildMallHandler();

  public GuildBossRankCacheManager bossRankCache = new GuildBossRankCacheManager();

  @Override
  public void shutdown() {
    this.save();

  }

  /**
   * 保存公会
   * 目前调用该save方法的模块，不希望该方法加锁
   *
   * @return 保存的数量
   */
  public int save() {
    List<GuildPO> guilds = getGuildList();
    int n = guilds.size();
    log.info("待保存的公会数量={}", n);
    game.facilities.getMongo().guild.saveAll(guilds);
    if (data != null) {
      game.db.kv.save(data);
    } else {
      log.error("在紧急入库执行中，公会data==null");
    }
    return n;
  }

  @NoteField(value = "Map<公会id,公会>")
  private Map<String, GuildPO> guildMap;

  @JsonIgnore
  public GuildManageAction action;


  @JsonIgnore
  @NoteField(value = "需要解散的公会")
  private List<GuildPO> disbandGuild;

  @Override
  public void initIndependent(GameBody game) throws Exception {
    super.initIndependent(game);
    bossRankCache.initIndependent(game);
  }

  @Override
  public void initDependent() throws Exception {
    data = new KvLoader<>(game, GuildSPO.class, KvMongo.KEY_GUILD_DATA).getBySrvId();

    if (action == null) {
      action = new GuildManageAction();
    }
    guildMap = new HashMap<>();

    // 从数据库读取数据
    List<GuildPO> rank = game.facilities.getMongo().guild.findAll();
    autoCreate(rank.size());
    if (!rank.isEmpty()) {
      for (GuildPO guild : rank) {
        guild.initialize(game);
        guildMap.put(guild.uid, guild);
      }
    }

//        fixGuild();
    if (mallHandler == null)
      mallHandler = new GuildMallHandler();
//        fixGuild();
    bossRankCache.initDependent();

    game.rpcRecv().onRequestResponseTemplate(RpcCommonPath.GUILD_VIEW_DETAIL_G2G, StringRef.class, this::onGuildViewDetailHandler);
  }

  private GuildViewDetailResp onGuildViewDetailHandler(RpcMsgHead head, StringRef guildIdRef) {
    GuildPO guild = game.res.guild.getGuild(guildIdRef.value());
    return new GuildViewDetailResp(guild);
  }


  /**
   * 新区自动生成20个公会
   *
   * @param size 当前公会数量
   */
  public void autoCreate(int size) {
    if (game.status.getOpenDay() > GDGuild.basic.FAKE_GUILD_DAY || size > 0) {
      return;
    }
    int num = GDGuild.basic.FAKE_GUILD_NUM + XT.randomIndex(GDGuild.basic.FAKE_GUILD_NUM_RANDOM);
    List<String> names = game.table.name.guild.getName(num);
    List<InstanceRsRow> inss = XT.randomPick(game.table.ins.rs.getList(), num, true);
    for (int i = 0; i < num; i++) {
      String name = names.get(i);
      InstanceRsRow rsRow = inss.get(i);
      // 创建一个虚拟的会长
      RoleSnapshot snap = new RoleSnapshot().readByInstanceRow(rsRow);
      snap.activeTime = System.currentTimeMillis();
      snap.base.vip = GDGuild.basic.VIP_LEVEL_REQUIRED;
      snap.base.level = GDGuild.basic.FAKE_GUILD_PRESIDENT_LEVEL;
      createRobotGuild(snap, name);
    }
  }

  private void createRobotGuild(RoleSnapshot snap, String guildName) {
    // 满足条件则开始创建公会
    GuildPO guild = new GuildPO();
    guild.initialize(game);
    // 生成公会基本信息
    String guildNo = data.newGuildNo(game);

    guild.basic.randomData(snap, guildName, guildNo, game);

    // 公会成员添加
    guild.member.addMember(snap);
    // 成员列表里的职位也改一下
    guild.member.getMember(snap.uid).performance.position = GDGuild.position.PRESIDENT;

    guild.basic.presidentId = snap.uid;
    // 把新公会放入内存
    guildMap.put(guild.uid, guild);

    game.facilities.getMongo().guild.insert(guild);
    //成功创建公会
  }

  /**
   * 清除所有生成的公会
   */
  public void fixGuild() {
    Iterator<GuildPO> it = getRank().iterator();
    while (it.hasNext()) {
      GuildPO guild = it.next();
      action.autoDisbandGuild(guild);
      it.remove();
    }
  }

  public Comparator<GuildPO> guildComparator() {
    return Comparator.comparing((GuildPO a) -> -a.basic.level)
            .thenComparing(a -> -a.basic.power)
            .thenComparing(a -> a.basic.powerTimeStamp);
  }

  public synchronized void createGuild(Role role, String guildName, int pattern, int background, String declaration, boolean authentication, int levelRequire, long powerRequire) {
    // 正常玩家检测
    //  超级用户跳过逻辑判断
//        if (!role.getStatus()) {
    GuildCreatedEvent createdEvent = new GuildCreatedEvent(role);
    EcResult<?> r = action.checkCreateGuild(role, guildName, pattern, background, createdEvent);
    if (!r.ok()) {
      return;
    }
//        }
    // 满足条件则开始创建公会
    GuildPO guild = new GuildPO();
    guild.initialize(game);
    // 生成公会基本信息
    String guildNo = data.newGuildNo(role);

    EcResult<?> r_basic = guild.basic.setData(guild, role, guildName, pattern, background, guildNo, declaration, authentication, levelRequire, powerRequire);
    if (!r_basic.ok())
      return;
    // 判断创建公会费用够不够
    new MixRes(GDGuild.basic.CREATE_COST).consumeDirect(role, null);

    guild.basic.presidentId = role.getUid();
    // 把新公会放入内存
    guildMap.put(guild.uid, guild);

    // 把职位设成会长
    role.getRes().guild.performance.position = GDGuild.position.PRESIDENT;
    // 公会成员添加
    guild.member.addMember(role, GDGuild.position.PRESIDENT);
    // 成员列表里的职位也改一下
    guild.member.getMember(role.getUid()).performance.position = GDGuild.position.PRESIDENT;

    role.getGame().notice.message(role, 310445, "恭喜您，公会创建成功，快去招募成员吧");
    // 把公会数据存入数据库
    role.getGame().facilities.getMongo().guild.insert(guild);
    //成功创建公会a
    role.getHistory().action.hadAGuild();
    role.getHistory().action.createGuild();
    role.getBase().updatePower();
    role.sendNow(new GuildBossDataResp(role.getRes().guild.getGuild().boss));
    role.sendNow(new MyGuildBossDataResp(role));
    createGuildLamp(role, guild);
//        role.sendNow(new GuildBossDataResp(role.getGame().res.guild.));
    createdEvent.setGuild(guild);
    publishEvent(game, createdEvent);
  }

  private void createGuildLamp(Role role, GuildPO guild) {
    List<ChatContentParam> params = new ArrayList<>();
    params.add(ChatContentParam.c(role.getBase().name));
    params.add(ChatContentParam.c(guild.basic.guildName));
    // 公会id给前端用
    params.add(ChatContentParam.c(ChatContentParam.TYPE_GUILD_ID, guild.uid));
    role.getGame().notice.lampOnline(role, GDNotice.TextId.CREATE_GUILD, params);
  }


  /**
   * 获取单个公会信息
   */
  public GuildPO getGuild(String guildIdHex) {
    return guildMap.get(guildIdHex);
  }


  /**
   * 获取全部公会信息
   */
  public List<GuildPO> getGuildList() {
    if (guildMap != null) {
      return new ArrayList<>(guildMap.values());
    }
    return new ArrayList<>();
  }

  /**
   * 移除公会
   */
  public synchronized GameResult<Void> deleteGuild(Role role) {
    String uid = role.getRes().guild.uid;
    // 验证能否解散
    GameResult<Void> r = action.disbandGuild(role);

    if (!r.ok()) {
      return r;
    }
    log.info("玩家{}主动解散了公会,玩家唯一id为{}", role.getBase().name, role.getUid());
    // 执行删除逻辑
    removeGuild(role.getGame(), uid);
    role.getGame().notice.message(role, 310446, "解散成功");
    return r.success();
  }

  /**
   * 删除公会
   */
  public void removeGuild(GameBody game, String uid) {
    // 从内存中删除
    guildMap.remove(uid);
    data.disbandMap.put(uid, System.currentTimeMillis());
    // 从数据库删除一下
    GameMongoDao mongoDao = game.facilities.getMongo();
    mongoDao.guild.deleteById(uid);

//        game.res.guild.delete(guildIdHex);
  }

  @Override
  public void onWeekSpan() {
    super.onWeekSpan();
    if (guildMap.isEmpty())
      return;
    guildMap
            .values()
            .forEach(GuildPO::onWeekSpan);
  }

  @Override
  public void onDaySpan() {
    super.onDaySpan();
    if (guildMap.isEmpty()) {
      return;
    }
    guildMap
            .values()
            .forEach(GuildPO::onDaySpan);
    data.onDaySpan();
  }

  /**
   * 找出玩家可以直接加入的公会列表
   */
  public GuildPO findAvailableGuild(Role role) {
    List<GuildPO> list = getGuildList()
            .stream()
            .filter(a -> !a.basic.authentication
                    && a.basic.levelRequired <= role.getBase().level
                    && a.basic.memberNum < a.basic.memberLimit
                    && a.basic.powerRequire <= role.getBase().power
                    && a.basic.levelRequired <= role.getBase().level)
            .collect(Collectors.toList());
    if (list.isEmpty())
      return null;
    else
      return list.get(0);
  }

  public int getSortedRankIndex(String uid) {
    List<GuildPO> rank = getRank();
    int size = rank.size();
    for (int i = 0; i < size; i++) {
      if (StringUtils.equals(uid, rank.get(i).uid))
        return i;
    }
    return -1;
  }

  public List<GuildPO> getRank() {
    return guildMap.values().stream().sorted(guildComparator()).collect(Collectors.toList());
  }

  public void recordDisbandGuild(GuildPO guild) {
    if (disbandGuild == null)
      disbandGuild = new LinkedList<>();
    disbandGuild.add(guild);
  }

  public void sendRankResp(Role role) {
    List<GuildRankItem> rank = new ArrayList<>();

    List<GuildPO> totalRank = game.res.guild.getRank();
    int rankSize = Math.min(totalRank.size(), GDGuild.RANK_LIMIT);
    if (rankSize == GDGuild.START_VALUE) {
      return;
    }
    for (GuildPO guild : totalRank.subList(GDGuild.START_VALUE, rankSize)) {
      rank.add(new GuildRankItem(guild.uid, guild.active.activity, guild.basic));
    }
    role.sendNow(new GuildRankResp(null, -1, rank));
  }
}
